﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.IO;



namespace Crypt_Tranceiver
{
    public class work_list
    {
        public String Remote;
        public String Local; 
        public String Oper;
        public String Req_Res;
        public int Seqno;
        public String Error;
        public int Length;
        public String Date;

        public String Direction;

        public const String CMD_BYE = "BYE";
        public const String FILE_START = "FILE_START";
        public const String FILE_SEND = "FILE_SEND";
        public const String FILE_ACK = "FILE_ACK";
        public const String FILE_END = "FILE_END";
        public const String MSG_SEND = "MSG_SEND";
        public const String MSG_ACK = "MSG_ACK";
        public const String SERVER_START = "SERVER_START";
        public const String SERVER_STOP = "SERVER_STOP";
        public const String MISC_LOG = "MISC_LOG";
        public const String MISC_CHAT_REC = "MISC_CHAT_REC";
        public const String MISC_FILE_DEKEY = "MISC_FILE_DEKEY";

        public const String SES_REMOTE    = "MSG_REMOTE=";
        public const String SES_LOCAL  = ",MSG_LOCAL=";
        public const String SES_OPER  = ",MSG_OPER=";
        public const String SES_REQS   = ",MSG_REQS=";
        public const String SES_SEQNO = ",MSG_SEQ=";
        public const String SES_ERROR = ",MSG_ERR=";
        public const String SES_LEN   = ",MSG_LEN=";
        public const String SES_DATA  = ",MSG_DATA=";

        public const String DIR_REQ = "DIR_REQ";
        public const String DIR_RES = "DIR_RES";

        public const String ERROR_OK = "OK";
        public const String ERROR_NOK = "NOK";
        public const String ERROR_FILE_RETRY = "FILE_RETRY";
        public const String ERROR_FILE_REFUSE = "FILE_REFUSE";
        public const String ERROR_FILE_SIGN_INVALID = "FILE_SIGN_INVALID";

        public const String CLIENT_CONNECT = "CONNECT";
        public const String CLIENT_ACCEPT = "CLIENT_ACCEPT";



        public const String DIR_IN = "DIR_IN";
        public const String DIR_OUT = "DIR_OUT";

        public const int file_seg_size = 1024;
        

    }

    public partial class Form_Main : Form
    {
        private Socket client;
        private bool connected = false;
        private String send_file_name;
        private int send_file_seqno;
        private int send_file_next_seqno;
        private String send_file_hash;
        private String send_file_enkey;
        private String send_file_eniv;
        private BinaryReader send_file_reader = null;
        private int send_file_size;
        private bool send_file_flg = false;
        private file_cryptor send_file_encryptor = null;


        private String save_file_name;
        private String save_file_name_temp;
        private BinaryWriter save_file_writer;
        private TextWriter save_file_info_writer;
        private String save_file_hash;
        private String save_file_sign;
        private int save_file_size;
        private String save_file_dekey;
        private String save_file_deiv;
        private file_cryptor save_file_decryptor = null;

        Random ro = new Random();

        

        private ManualResetEvent file_next_seg_event = new ManualResetEvent(false);
        private ManualResetEvent file_name_event = new ManualResetEvent(false);
        private ManualResetEvent file_decrypt_key_event = new ManualResetEvent(false);

        private void bg_work()
        {
            send_file_seqno = 0;
            while (true)
            {
                bg_work_outqueue();
                bg_work_inqueue();
                bg_work_sendfile();
            }
        }

        private String bg_message_encode(work_list item)
        {
            String msg;

            msg  = work_list.SES_REMOTE + item.Remote;
            msg += work_list.SES_LOCAL + item.Local;
            msg += work_list.SES_OPER + item.Oper;
            msg += work_list.SES_REQS + item.Req_Res;
            msg += work_list.SES_SEQNO + item.Seqno;
            msg += work_list.SES_ERROR + item.Error;
            msg += work_list.SES_LEN + item.Length;
            msg += work_list.SES_DATA + item.Date;

            return msg;
        }

        public static work_list bg_message_decode(String msg)
        {
            work_list item = new work_list();
            int pos;
            String s;

            pos = msg.IndexOf(work_list.SES_DATA);
            if (pos >= 0)
            {
                item.Date = msg.Substring(pos + work_list.SES_DATA.Length);
                s = msg.Remove(pos);
            }
            else
            {
                return null;
            }

            pos = s.IndexOf(work_list.SES_LEN);
            if(pos >= 0)
            {
                s = s.Substring(pos + work_list.SES_LEN.Length);
                item.Length = Convert.ToInt32(s, 10);
                s = msg.Remove(pos);
            }
            else
            {
                return null;
            }

            pos = s.IndexOf(work_list.SES_ERROR);
            if(pos >= 0)
            {
                s = s.Substring(pos + work_list.SES_ERROR.Length);
                item.Error = s;
                s = msg.Remove(pos);
            }
            else
            {
                return null;
            }

            pos = s.IndexOf(work_list.SES_SEQNO);
            if(pos >= 0)
            {
                s = s.Substring(pos + work_list.SES_SEQNO.Length);
                item.Seqno = Convert.ToInt32(s, 10);
                s = msg.Remove(pos);
            }
            else
            {
                return null;
            }

            pos = s.IndexOf(work_list.SES_REQS);
            if(pos >= 0)
            {
                s = s.Substring(pos + work_list.SES_REQS.Length);
                item.Req_Res = s;
                s = msg.Remove(pos);
            }
            else
            {
                return null;
            }

            pos = s.IndexOf(work_list.SES_OPER);
            if(pos >= 0)
            {
                s = s.Substring(pos + work_list.SES_OPER.Length);
                item.Oper = s;
                s = msg.Remove(pos);
            }
            else
            {
                return null;
            }

            pos = s.IndexOf(work_list.SES_LOCAL);
            if(pos >= 0)
            {
                s = s.Substring(pos + work_list.SES_LOCAL.Length);
                item.Local = s;
                s = msg.Remove(pos);
            }
            else
            {
                return null;
            }

            pos = s.IndexOf(work_list.SES_REMOTE);
            if(pos >= 0)
            {
                s = s.Substring(pos + work_list.SES_REMOTE.Length);
                item.Remote = s;
                s = msg.Remove(pos);
            }
            else
            {
                return null;
            }


            return item;
        }

        private bool bg_send(String remote, String msg)
        {
            bool flg = false;
            if (AsynchronousSocketListener.client_list != null)
            {
                if (AsynchronousSocketListener.client_list.Count > 0)
                {
                    foreach (StateObject state in AsynchronousSocketListener.client_list)
                    {
                        if (state.workSocket.RemoteEndPoint.ToString() == remote)
                        {
                            AsynchronousSocketListener.Send(state.workSocket, msg);
                            //log_add_thread("向" + remote + "发送数据：" + msg);
                            flg = true;
                            break;
                        }
                    }
                }
            }
            if((flg == false) && (client != null))
            {
                AsynchronousClient.Send(client, msg);
                //log_add_thread("向" + remote + "发送数据：" + msg);
                flg = true;
            }

            return flg;
        }

        /**
         * 输入队列
         */
        private void bg_work_inqueue()
        {
            work_list item;

            while (tcp_inlist.Count != 0)
            {
                /*
                 * TCP输入队列
                 */
                tcp_in_mutex.WaitOne();
                /*输入队列不为空*/
                item = null;
                if (tcp_inlist.Count > 0)
                {
                    item = tcp_inlist.Dequeue();
                    //log_add_thread("收到" + item.Remote+"发来数据："+item.Date);
                }
                tcp_in_mutex.ReleaseMutex();
                if (item == null)
                {
                    break;
                }
                else
                {
                    switch (item.Oper)
                    {
                        case work_list.SERVER_STOP:
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                work_list status = new work_list();
                                item.Error = work_list.ERROR_OK;

                                item.Direction = work_list.DIR_IN;
                                status_mutex.WaitOne();
                                status_inlist.Enqueue(item);
                                status_mutex.ReleaseMutex();
                            }
                            else
                            {
                            }
                            break;
                        case work_list.CMD_BYE:
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                if (AsynchronousSocketListener.client_list.Count > 0)
                                {
                                    foreach (StateObject state in AsynchronousSocketListener.client_list)
                                    {
                                        if (state.workSocket.RemoteEndPoint.ToString() == item.Date)
                                        {
                                            state.workSocket.Close();
                                            AsynchronousSocketListener.client_list.Remove(state);
                                            break;
                                        }
                                    }
                                }
                                work_list status = new work_list();
                                status.Error = work_list.ERROR_OK;

                                status.Direction = work_list.DIR_IN;
                                status_mutex.WaitOne();
                                status_inlist.Enqueue(status);
                                status_mutex.ReleaseMutex();
                            }
                            else
                            {
                            }
                            break;
                        case work_list.FILE_START:
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                String log_item = "收到文件传输请求，";

                                status_mutex.WaitOne();
                                work_list status = new work_list();
                                status.Req_Res = work_list.DIR_REQ;
                                status.Error = work_list.ERROR_OK;
                                status.Oper = work_list.FILE_START;
                                status.Remote = item.Remote;
                                status.Local = item.Local;
                                status_inlist.Enqueue(status);
                                status_mutex.ReleaseMutex();
                                file_name_event.WaitOne();
                                if (save_file_name != null)
                                {
                                    if (File.Exists(save_file_name))
                                    {
                                        File.Delete(save_file_name);
                                    }
                                    log_item += "保存文件名为：" + save_file_name;
                                    int pos = item.Date.IndexOf(" ");
                                    String hash = item.Date.Remove(pos);
                                    String s = item.Date.Substring(pos + 1);
                                    pos = s.IndexOf(" ");
                                    int len = Convert.ToInt32(s.Remove(pos), 10);


                                    String s1 = s.Substring(pos + 1);
                                    pos = s1.IndexOf(" ");
                                    String iv = s1.Remove(pos);
                                    String sign = s1.Substring(pos + 1);
                                    save_file_deiv = iv;
                                    save_file_size = len;
                                    save_file_hash = hash;
                                    save_file_sign = sign;
                                    item.Seqno = 0;
                                    //检查是否需要重传
                                    if (File.Exists(save_file_name_temp + ".part") && File.Exists(save_file_name_temp + ".temp"))
                                    {
                                        BinaryReader reader = new BinaryReader(File.Open((save_file_name_temp + ".part"), FileMode.Open, FileAccess.Read));
                                        TextReader info_reader = new StreamReader(save_file_name_temp + ".temp");
                                        String hash_file = info_reader.ReadLine();
                                        String deiv_file = info_reader.ReadLine();
                                        int len_file = Convert.ToInt32(info_reader.ReadLine(), 10);
                                        String sign_file = info_reader.ReadLine();
                                        /*文件Hash相等的才是同一个文件*/
                                        if (hash == hash_file)
                                        {
                                            int i = 0;
                                            int segs = (int)(reader.BaseStream.Length / work_list.file_seg_size + 1);
                                            int crc32, crc;
                                            Byte[] buff = new Byte[work_list.file_seg_size];
                                            int count;
                                            //计算重传的位置
                                            for (i = 0; i < segs; i++)
                                            {
                                                crc32 = Convert.ToInt32(info_reader.ReadLine(), 10);
                                                count = reader.Read(buff, 0, work_list.file_seg_size);
                                                crc = CRC32.GetCRC32(buff, count);
                                                if (crc32 == crc)
                                                {
                                                    item.Seqno++;
                                                    /*传送的文件块不大于单位文件块，并且序号为最后一个*/
                                                    if (item.Seqno == segs - 1)
                                                    {
                                                        item.Oper = work_list.FILE_END;
                                                        item.Error = work_list.ERROR_OK;
                                                        item.Req_Res = work_list.DIR_REQ;
                                                        reader.Close();
                                                        info_reader.Close();
                                                        File.Move((save_file_name_temp + ".part"), save_file_name);
                                                        log_add_thread(save_file_name + "传输完毕，" + "大小为" + save_file_size + "字节。");
                                                        break;
                                                    }
                                                }
                                                else
                                                {
                                                    break;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            item.Seqno = 0;
                                        }
                                        reader.Close();
                                        info_reader.Close();
                                    }
                                    if (item.Oper != work_list.FILE_END)
                                    {
                                        //从第一个字节开始传输，即新文件传输
                                        if (item.Seqno == 0)
                                        {
                                            save_file_writer = new BinaryWriter(File.Create(save_file_name_temp + ".part"));

                                            save_file_info_writer = new StreamWriter(File.Create(save_file_name_temp + ".temp"));
                                            save_file_info_writer.WriteLine(hash);
                                            save_file_info_writer.WriteLine(iv);
                                            save_file_info_writer.WriteLine(len);
                                            save_file_info_writer.WriteLine(sign);
                                        }
                                        else
                                        {
                                            int r = ro.Next();

                                            save_file_writer = new BinaryWriter(File.Open((save_file_name_temp + ".part"), FileMode.Append, FileAccess.Write));
                                            save_file_writer.Seek(item.Seqno * work_list.file_seg_size, SeekOrigin.Begin);
                                            File.Move((save_file_name_temp + ".temp"), (save_file_name_temp + ".temp" + r));
                                            save_file_info_writer = new StreamWriter(File.Open((save_file_name_temp + ".temp"), FileMode.Create, FileAccess.Write));
                                            StreamReader file_info_reader = new StreamReader(File.Open((save_file_name_temp + ".temp" + r), FileMode.Open, FileAccess.Read));
                                            save_file_info_writer.WriteLine(file_info_reader.ReadLine());
                                            save_file_info_writer.WriteLine(file_info_reader.ReadLine());
                                            save_file_info_writer.WriteLine(file_info_reader.ReadLine());
                                            save_file_info_writer.WriteLine(file_info_reader.ReadLine());
                                            for (int i = 0; i < item.Seqno; i++)
                                            {
                                                save_file_info_writer.WriteLine(file_info_reader.ReadLine());
                                            }

                                        }
                                        log_item += "从字节" + item.Seqno * work_list.file_seg_size + "开始传输。";
                                        item.Error = work_list.ERROR_FILE_RETRY;
                                    }
                                }
                                else
                                {
                                    log_item += "未指定保存文件名，传输中断。";
                                    item.Error = work_list.ERROR_FILE_REFUSE;
                                }
                                item.Req_Res = work_list.DIR_RES;
                                item.Oper = work_list.FILE_ACK;
                                item.Remote = remote;
                                item.Local = local;
                                item.Date = null;
                                log_add_thread(log_item);


                                tcp_out_mutex.WaitOne();
                                tcp_outlist.Enqueue(item);
                                tcp_out_mutex.ReleaseMutex();
                            }
                            break;
                        case work_list.FILE_SEND:
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                //首先取得文件的Hash值
                                int pos = item.Date.IndexOf(" ");
                                item.Oper = work_list.FILE_ACK;
                                item.Req_Res = work_list.DIR_RES;
                                if (pos >= 0)
                                {
                                    String hash = item.Date.Remove(pos);
                                    String s = item.Date.Substring(pos + 1);
                                    //获取该数据段的长度和crc32
                                    Byte[] buff = Convert.FromBase64String(s);
                                    Byte[] tmp_buff = new Byte[work_list.file_seg_size];
                                    int crc32, crc, len;

                                    len = buff[0];
                                    len <<= 8;
                                    len |= buff[1];
                                    len <<= 8;
                                    len |= buff[2];
                                    len <<= 8;
                                    len |= buff[3];

                                    crc32 = buff[4];
                                    crc32 <<= 8;
                                    crc32 |= buff[5];
                                    crc32 <<= 8;
                                    crc32 |= buff[6];
                                    crc32 <<= 8;
                                    crc32 |= buff[7];

                                    for (int i = 0; i < len; i++)
                                    {
                                        tmp_buff[i] = buff[8 + i];
                                    }
                                    crc = CRC32.GetCRC32(tmp_buff, len);
                                    if (crc == crc32)
                                    {
                                        item.Error = work_list.ERROR_OK;
                                        pos = item.Seqno * work_list.file_seg_size;
                                        if (pos < save_file_writer.BaseStream.Position)
                                        {
                                            int r = ro.Next();
                                            save_file_writer.Seek(pos, SeekOrigin.Begin);
                                            save_file_info_writer.Close();
                                            File.Move((save_file_name_temp + ".temp"), (save_file_name_temp + ".temp" + r));

                                            save_file_info_writer = new StreamWriter(File.Open((save_file_name_temp + ".temp"), FileMode.Create, FileAccess.Write));
                                            StreamReader file_info_reader = new StreamReader(File.Open((save_file_name_temp + ".temp" + r), FileMode.Open, FileAccess.Read));
                                            save_file_info_writer.WriteLine(file_info_reader.ReadLine());
                                            save_file_info_writer.WriteLine(file_info_reader.ReadLine());
                                            save_file_info_writer.WriteLine(file_info_reader.ReadLine());
                                            save_file_info_writer.WriteLine(file_info_reader.ReadLine());
                                            for (int i = 0; i < item.Seqno; i++)
                                            {
                                                save_file_info_writer.WriteLine(file_info_reader.ReadLine());
                                            }
                                        }
                                        else if (pos > save_file_writer.BaseStream.Position)
                                        {

                                        }

                                        save_file_writer.Write(tmp_buff, 0, len);
                                        save_file_info_writer.WriteLine(crc);
                                        int segs = (int)(save_file_size / work_list.file_seg_size + 1);
                                        work_list status = new work_list();
                                        /*传送的文件块不大于单位文件块，并且序号为最后一个*/
                                        if ((len <= work_list.file_seg_size) && (item.Seqno == segs - 1))
                                        {
                                            save_file_writer.Close();
                                            String hashall = FileHash.getMD5Hash(save_file_name_temp + ".part");

                                            if (hashall == save_file_hash)
                                            {
                                                //解密文件
                                                status_mutex.WaitOne();
                                                status.Req_Res = work_list.DIR_REQ;
                                                status.Error = work_list.ERROR_OK;
                                                status.Oper = work_list.MISC_FILE_DEKEY;
                                                status.Remote = item.Remote;
                                                status.Local = item.Local;
                                                status_inlist.Enqueue(status);
                                                status_mutex.ReleaseMutex();
                                                file_decrypt_key_event.WaitOne();
                                                if (save_file_dekey != null)
                                                {
                                                    save_file_decryptor = new file_cryptor(save_file_dekey, save_file_deiv, false);
                                                    save_file_decryptor.DecryptFile(save_file_name_temp + ".part", save_file_name_temp + ".dec");
                                                    if (remote_rsa_key != null)
                                                    {
                                                        //验证签名
                                                        byte[] src = File.ReadAllBytes(save_file_name_temp + ".dec");
                                                        if (rsa_file.VerifySignedHash(src, Convert.FromBase64String(save_file_sign), remote_rsa_key))
                                                        {
                                                            item.Oper = work_list.FILE_END;
                                                            item.Error = work_list.ERROR_OK;
                                                            item.Req_Res = work_list.DIR_REQ;
                                                            save_file_writer.Close();
                                                            save_file_info_writer.Close();
                                                            File.Move((save_file_name_temp + ".dec"), save_file_name);
                                                            log_add_thread(save_file_name + "传输完毕，" + "大小为" + save_file_size + "字节，签名已经验证。");
                                                        }
                                                        else
                                                        {
                                                            item.Oper = work_list.FILE_END;
                                                            item.Error = work_list.ERROR_FILE_SIGN_INVALID;
                                                            item.Req_Res = work_list.DIR_REQ;
                                                            save_file_writer.Close();
                                                            save_file_info_writer.Close();
                                                            File.Move((save_file_name_temp + ".dec"), save_file_name);
                                                            log_add_thread(save_file_name + "传输完毕，" + "大小为" + save_file_size + "字节，但是验证签名失败！");
                                                        }
                                                    }
                                                    else
                                                    {
                                                        item.Oper = work_list.FILE_END;
                                                        item.Error = work_list.ERROR_FILE_SIGN_INVALID;
                                                        item.Req_Res = work_list.DIR_REQ;
                                                        save_file_writer.Close();
                                                        save_file_info_writer.Close();
                                                        File.Move((save_file_name_temp + ".dec"), save_file_name);

                                                        log_add_thread(save_file_name + "传输完毕，" + "大小为" + save_file_size + "字节，没有用于验证签名的公钥！");
                                                    }
                                                }                                                
                                            }
                                            else
                                            {
                                                if (MessageBox.Show(save_file_name + "传输失败，是否重新传输", "询问", MessageBoxButtons.YesNo) == DialogResult.Yes)
                                                {
                                                    save_file_writer = new BinaryWriter(File.Open(save_file_name_temp + ".part", FileMode.Append, FileAccess.Write));
                                                    item.Oper = work_list.FILE_ACK;
                                                    item.Error = work_list.ERROR_FILE_RETRY;
                                                    item.Req_Res = work_list.DIR_RES;
                                                    log_add_thread(save_file_name + "传输失败，Hash未通过，重新传输。");
                                                }
                                                else
                                                {
                                                    save_file_writer.Close();
                                                    save_file_info_writer.Close();
                                                    item.Error = work_list.ERROR_NOK;
                                                    log_add_thread(save_file_name + "传输失败，Hash未通过，用户取消重传。");
                                                }

                                            }

                                        }
                                        status_mutex.WaitOne();
                                        status.Req_Res = work_list.DIR_REQ;
                                        status.Error = work_list.ERROR_OK;
                                        status.Oper = work_list.FILE_SEND;
                                        status.Direction = work_list.DIR_IN;
                                        status.Remote = item.Remote;
                                        status.Local = item.Local;
                                        status.Date = Convert.ToString(segs, 10);
                                        status.Seqno = item.Seqno + 1;
                                        status_inlist.Enqueue(status);
                                        status_mutex.ReleaseMutex();
                                        //file_name_event.WaitOne();
                                        Console.WriteLine("收到第" + item.Seqno + "个文件分段。\r\n");
                                    }
                                    else
                                    {
                                        item.Error = work_list.ERROR_FILE_RETRY;
                                    }
                                }
                                else
                                {
                                    item.Error = work_list.ERROR_NOK;
                                    save_file_writer.Close();
                                    save_file_info_writer.Close();
                                }

                                //Console.WriteLine(work_item.Date);
                                item.Date = save_file_hash;
                                item.Remote = remote;
                                item.Local = local;
                                tcp_out_mutex.WaitOne();
                                tcp_outlist.Enqueue(item);
                                tcp_out_mutex.ReleaseMutex();
                            }
                            break;
                        case work_list.FILE_ACK:
                            if (item.Req_Res == work_list.DIR_RES)
                            {
                                switch (item.Error)
                                {
                                    case work_list.ERROR_OK:
                                        send_file_next_seqno = item.Seqno + 1;
                                        send_file_flg = true;
                                        file_next_seg_event.Set();
                                        break;
                                    case work_list.ERROR_NOK:
                                        send_file_flg = false;
                                        break;
                                    case work_list.ERROR_FILE_RETRY:
                                        send_file_next_seqno = item.Seqno;
                                        send_file_flg = true;
                                        file_next_seg_event.Set();
                                        break;
                                    case work_list.ERROR_FILE_REFUSE:
                                        send_file_flg = false;
                                        break;
                                    default: break;

                                }
                                item.Direction = work_list.DIR_IN;
                                status_mutex.WaitOne();
                                status_inlist.Enqueue(item);
                                status_mutex.ReleaseMutex();
                            }
                            break;
                        case work_list.FILE_END:
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                send_file_flg = false;
                                item.Direction = work_list.DIR_IN;
                                item.Date = send_file_name;
                                item.Length = item.Date.Length;
                                item.Remote = remote;
                                item.Local = local;
                                status_mutex.WaitOne();
                                status_inlist.Enqueue(item);
                                status_mutex.ReleaseMutex();
                                //file_name_event.WaitOne();
                                send_file_name = null;
                                send_file_seqno = 0;
                                send_file_next_seqno = 0;
                                send_file_hash = null;
                                send_file_enkey = null;
                                send_file_eniv = "1234567890";
                                send_file_reader = null;
                                send_file_flg = false;
                            }
                            break;
                        case work_list.MSG_SEND:
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                status_mutex.WaitOne();
                                item.Direction = work_list.DIR_IN;
                                status_inlist.Enqueue(item);
                                status_mutex.ReleaseMutex();
                            }
                            break;
                        case work_list.MSG_ACK:
                            break;
                        default:
                            Console.WriteLine("Should not come here.");
                            break;
                    }
                }
            }
        }


        /**
         * 输出队列
         */
        private void bg_work_outqueue()
        {
            work_list item = null;
            work_list status = new work_list();

            while (tcp_outlist.Count > 0)
            {
                tcp_out_mutex.WaitOne();
                if (tcp_outlist.Count > 0)
                {
                    item = null;
                    item = tcp_outlist.Dequeue();
                }
                tcp_out_mutex.ReleaseMutex();

                if (item == null)
                {
                    break;
                }
                else
                {
                    status.Date = item.Date;
                    status.Req_Res = item.Req_Res;
                    status.Error = work_list.ERROR_OK;
                    status.Remote = item.Remote;
                    status.Local = item.Local;
                    status.Oper = item.Oper;
                    switch (item.Oper)
                    {
                        case work_list.SERVER_START:
                            AsynchronousSocketListener.StartListening(local_listen_port);
                            break;
                        case work_list.SERVER_STOP:
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                if (AsynchronousSocketListener.client_list.Count > 0)
                                {
                                    foreach (StateObject state in AsynchronousSocketListener.client_list)
                                    {
                                        if (state.workSocket.RemoteEndPoint.ToString() == item.Date)
                                        {
                                            item.Date = state.workSocket.RemoteEndPoint.ToString();
                                            item.Error = work_list.ERROR_OK;
                                            item.Length = item.Date.Length;
                                            byte[] msg = Encoding.UTF8.GetBytes(bg_message_encode(item));
                                            state.workSocket.Send(msg);
                                            state.workSocket.Shutdown(SocketShutdown.Both);
                                            state.workSocket.Close();
                                            AsynchronousSocketListener.client_list.Remove(state);
                                            break;
                                        }
                                    }
                                }
                            }
                            else
                            {
                            }
                            AsynchronousSocketListener.StopListening();
                            break;
                        case work_list.CLIENT_CONNECT://连接服务端
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                String ip;
                                int pos, port;
                                pos = item.Remote.IndexOf(":");
                                ip = item.Remote.Remove(pos);
                                port = Convert.ToInt32(item.Remote.Substring(pos + 1), 10);
                                client = AsynchronousClient.StartClient(ip, port);
                            }
                            else
                            {
                            }
                            break;
                        case work_list.CMD_BYE:
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                
                                item.Error = work_list.ERROR_OK;
                                item.Direction = work_list.DIR_OUT;
                                item.Date = client.LocalEndPoint.ToString();
                                item.Length = item.Date.Length;
                                String msg = bg_message_encode(item);
                                //AsynchronousClient.Send(client, msg);
                                bg_send(item.Remote, msg);
                                status_mutex.WaitOne();
                                status_inlist.Enqueue(item);
                                status_mutex.ReleaseMutex();
                            }
                            else
                            {
                            }
                            break;
                        case work_list.FILE_START:
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                send_file_seqno = 0;
                                send_file_flg = false;
                                int pos = item.Date.IndexOf(":");
                                send_file_enkey = item.Date.Remove(pos);
                                send_file_eniv = "1234567890";
                                send_file_name = item.Date.Substring(pos + 1);
                                //对原始文件进行签名
                                byte[] source = File.ReadAllBytes(send_file_name);
                                byte[] rsa_sign = rsa_file.HashAndSign(source, rsa_file.str_Private_Key);
                                String sign = Convert.ToBase64String(rsa_sign);
                                
                                //加密原始文件
                                send_file_encryptor = new file_cryptor(send_file_enkey, send_file_eniv, true);
                                send_file_encryptor.EncryptFile(send_file_name, send_file_name + ".enc");
                                send_file_hash = FileHash.getMD5Hash(send_file_name + ".enc");
                                send_file_reader = new BinaryReader(File.Open(send_file_name + ".enc", FileMode.Open));
                                send_file_size = (int)send_file_reader.BaseStream.Length;
                                item.Date = send_file_hash + " " + send_file_reader.BaseStream.Length + " " + send_file_eniv + " " + sign;
                                item.Error = work_list.ERROR_OK;
                                item.Length = item.Date.Length;
                                String msg = bg_message_encode(item);
                                //AsynchronousClient.Send(client, msg);
                                bg_send(item.Remote, msg);
                                log_add_thread("开始" + item.Remote + "发送文件" + send_file_name);
                            }
                            break;
                        case work_list.FILE_SEND:
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                send_file_flg = false;
                                item.Error = work_list.ERROR_OK;
                                item.Length = item.Date.Length;
                                String msg = bg_message_encode(item);
                                //AsynchronousClient.Send(client, msg);
                                bg_send(item.Remote, msg);
                                //status_mutex.WaitOne();
                               // status_inlist.Enqueue(status);
                                //status_mutex.ReleaseMutex();
                            }
                            else
                            {
                            }
                            break;
                        case work_list.FILE_ACK:
                            if (item.Req_Res == work_list.DIR_RES)
                            {
                                String msg = bg_message_encode(item);
                                //AsynchronousClient.Send(client, msg);
                                bg_send(item.Remote, msg);
                                status_mutex.WaitOne();
                                status_inlist.Enqueue(status);
                                status_mutex.ReleaseMutex();
                            }
                            break;
                        case work_list.FILE_END:
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                String msg = bg_message_encode(item);
                                //AsynchronousClient.Send(client, msg);
                                bg_send(item.Remote, msg);
                                status.Direction = work_list.DIR_OUT;
                                status.Date = save_file_name;
                                status.Length = status.Date.Length;
                                status_mutex.WaitOne();
                                status_inlist.Enqueue(status);
                                status_mutex.ReleaseMutex();
                                save_file_name = null;
                                save_file_name_temp = null;
                                save_file_writer = null;
                                save_file_info_writer = null;
                                save_file_hash = null;
                                save_file_sign = null;
                                save_file_size = 0;
                                save_file_dekey = null;
                                save_file_deiv = null;
                            }
                            break;
                        case work_list.MSG_SEND:
                            if (item.Req_Res == work_list.DIR_REQ)
                            {
                                item.Error = work_list.ERROR_OK;
                                item.Length = item.Date.Length;
                                String msg = bg_message_encode(item);
                                //AsynchronousClient.Send(client, msg);
                                bg_send(item.Remote, msg);
                                status_mutex.WaitOne();
                                status_inlist.Enqueue(status);
                                status_mutex.ReleaseMutex();
                            }
                            else
                            {
                            }
                            break;
                        case work_list.MSG_ACK:
                            if (item.Req_Res == work_list.DIR_RES)
                            {
                                item.Error = work_list.ERROR_OK;
                                item.Length = item.Date.Length;
                                String msg = bg_message_encode(item);                             
                                //AsynchronousClient.Send(client, msg);
                                bg_send(item.Remote, msg);
                                status_mutex.WaitOne();
                                status_inlist.Enqueue(status);
                                status_mutex.ReleaseMutex();
                            }
                            break;
                        default: break;
                    }
                }
                item = null;
            }
        }

        /*
         * 发送文件
         */
        private void bg_work_sendfile()
        {
            if ((send_file_flg == true) && (File.Exists(send_file_name)))
            {
                file_next_seg_event.WaitOne();
                try
                {
                    if (send_file_seqno == 0)
                    {
                        if ((send_file_reader != null) && (send_file_reader.BaseStream == null) || (send_file_reader == null))
                        {
                            
                            send_file_encryptor = new file_cryptor(send_file_enkey, send_file_eniv, true);
                            send_file_encryptor.EncryptFile(send_file_name, send_file_name + ".enc");
                            send_file_reader = new BinaryReader(File.Open(send_file_name + ".enc", FileMode.Open));
                        }
                    }
                    byte[] buff = new byte[work_list.file_seg_size + 64];
                    byte[] tmp_buff = new byte[work_list.file_seg_size + 4];
                    //byte[] dst;
                    int count;
                    int crc32;
                    if (send_file_seqno != send_file_next_seqno - 1)
                    {
                        send_file_reader.BaseStream.Seek(send_file_next_seqno * work_list.file_seg_size, SeekOrigin.Begin);
                    }
                    else
                    {
                        send_file_seqno = send_file_next_seqno;
                    }
                    if ((count = send_file_reader.Read(tmp_buff, 0, work_list.file_seg_size)) != 0)
                    {
                        work_list item = new work_list();
                        item.Req_Res = work_list.DIR_REQ;
                        item.Oper = work_list.FILE_SEND;
                        item.Remote = remote;
                        item.Local = local;
                        item.Seqno = send_file_seqno;
                        //send_file_encryptor.flush_stream();
                        //dst = send_file_encryptor.encryptor(tmp_buff, count);
                        //count = dst.Length;
                        crc32 = CRC32.GetCRC32(tmp_buff, count);
                        buff[4] = Convert.ToByte(((crc32 >> 24) & 0xFF));
                        buff[4 + 1] = Convert.ToByte(((crc32 >> 16) & 0xFF));
                        buff[4 + 2] = Convert.ToByte(((crc32 >> 8) & 0xFF));
                        buff[4 + 3] = Convert.ToByte(((crc32 >> 0) & 0xFF));
                        buff[0] = Convert.ToByte(((count >> 24) & 0xFF));
                        buff[0 + 1] = Convert.ToByte(((count >> 16) & 0xFF));
                        buff[0 + 2] = Convert.ToByte(((count >> 8) & 0xFF));
                        buff[0 + 3] = Convert.ToByte(((count >> 0) & 0xFF));
                        tmp_buff.CopyTo(buff, 8);
                        item.Date = send_file_hash + " " + Convert.ToBase64String(buff, 0, count + 8);//编码

                        item.Length = item.Date.Length;
                        tcp_out_mutex.WaitOne();
                        tcp_outlist.Enqueue(item);
                        tcp_out_mutex.ReleaseMutex();
                        send_file_seqno = send_file_next_seqno;
                        int segs = (int)(send_file_reader.BaseStream.Length / work_list.file_seg_size + 1);
                        if ((count <= work_list.file_seg_size) && (send_file_seqno == segs - 1))
                        {
                            
                            send_file_seqno = 0;
                            send_file_reader.Close();
                            send_file_reader = null;
                            file_next_seg_event.Reset();
                        }
                        send_file_flg = false;
                        //int point = send_file_seqno * send_file_size;
                        //int perzent = point * 100 / send_file_reader.BaseStream.Length;
                        
                        //Console.WriteLine(System.Text.Encoding.Default.GetString(Convert.FromBase64String("xL7X087dLWh0dHA6Ly93d3cubXp3dS5jb20v ")));//解码
                    }
                }
                catch (EndOfStreamException err)
                {
                    Console.WriteLine("{0} caught and ignored. " +
                        "Using default values.", err.GetType().Name);
                }
            }
        }

        /**/
        void log_add_thread(String log)
        {
            status_mutex.WaitOne();
            work_list item = new work_list();
            item.Req_Res = work_list.DIR_REQ;
            item.Error = work_list.ERROR_OK;
            item.Oper = work_list.MISC_LOG;
            item.Remote = remote;
            item.Local = local;
            item.Date = log;
            item.Length = log.Length;
            status_inlist.Enqueue(item);
            status_mutex.ReleaseMutex();
        }
    }
}